﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Webdiyer.WebControls.Mvc;
using ZSZ.Common;
using ZSZ.DTO;
using ZSZ.DTO.Enums;
using ZSZ.IService;
using ZSZ.Model;

namespace ZSZ.Service
{
    public partial class AdminUserService : BaseService<AdminUser>, IAdminUserService
    {
        #region 查询
        private IQueryable<AdminUser> GetJoinAll()
        {
            return GetAll()
                .Include(u => u.City)
                .Include(u => u.AdminUserRoles)
                .Include(u => u.AdminUserRoles.Select(ar => ar.Role))
                .AsNoTracking();
        }
        /// <summary>
        /// 获取分页数据
        /// </summary>
        /// <param name="options"></param>
        /// <param name="total"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        public AdminUserDTO[] GetPagedData(AdminUserSearchOptions options, out long total, int pageIndex = 1, int pageSize = 10)
        {
            IQueryable<AdminUser> entities = GetJoinAll();
            //.Include(nameof(AdminUser.AdminUserRoles))
            //.Include(nameof(AdminUser.AdminUserRoles) + "." + nameof(AdminUserRole.Role));
            if (options.BeginDate != null)
            {
                entities = entities.Where(u => DbFunctions.DiffDays(u.CreateDateTime, options.BeginDate) <= 0);
            }
            if (options.EndDate != null)
            {
                entities = entities.Where(u => DbFunctions.DiffDays(u.CreateDateTime, options.EndDate) >= 0);
            }
            if (!string.IsNullOrEmpty(options.Keywords))
            {
                entities = entities.Where(u => u.Name.Contains(options.Keywords) || u.PhoneNum.Contains(options.Keywords) || u.Email.Contains(options.Keywords));
            }

            return CurrentDal.GetPagedData(entities, out total, pageIndex, pageSize).ToList().Select(u => ToDTO(u)).ToArray();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="options">查询条件</param>
        /// <param name="pageIndex">当前页索引</param>
        /// <param name="pageSize">每页显示记录数</param>
        /// <returns></returns>
        public PagedList<AdminUserDTO> GetPagedData(AdminUserSearchOptions options, int pageIndex, int pageSize)
        {
            IQueryable<AdminUser> entities = GetJoinAll();
            if (options.BeginDate != null)
            {
                entities = entities.Where(u => DbFunctions.DiffDays(u.CreateDateTime, options.BeginDate) <= 0);
            }
            if (options.EndDate != null)
            {
                entities = entities.Where(u => DbFunctions.DiffDays(u.CreateDateTime, options.EndDate) >= 0);
            }
            if (!string.IsNullOrEmpty(options.Keywords))
            {
                entities = entities.Where(u => u.Name.Contains(options.Keywords) || u.PhoneNum.Contains(options.Keywords) || u.Email.Contains(options.Keywords));
            }

            //总记录数
            int totalItemCount = entities.Count();

            entities = entities.OrderByDescending(e => e.Id).Skip(pageSize * (pageIndex - 1)).Take(pageSize);

            return new PagedList<AdminUserDTO>(entities.ToList().Select(u => ToDTO(u)), pageIndex, pageSize, totalItemCount);
        }

        /// <summary>
        /// 获取用户
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public AdminUserDTO GetDTOById(long userId)
        {
            var users = GetJoinAll().Where(u => u.Id == userId);
            int count = users.Count();
            if (count <= 0)
            {
                return null;
            }
            else if (count == 1)
            {
                return ToDTO(users.Single());
            }
            else
            {
                throw new ApplicationException("获取到多个用户 Id 为" + userId + "的管理员");
            }
        }

        /// <summary>
        /// 获取用户
        /// </summary>
        /// <param name="userName"></param>
        /// <returns></returns>
        public AdminUserDTO GetByName(string userName)
        {
            var users = GetJoinAll().Where(u => u.Name == userName);
            int count = users.Count();
            if (count <= 0)
            {
                return null;
            }
            else if (count == 1)
            {
                return ToDTO(users.Single());
            }
            else
            {
                throw new ApplicationException("获取到多个用户名为" + userName + "的管理员");
            }
        }

        /// <summary>
        /// 用户名是否存在
        /// </summary>
        /// <param name="permName"></param>
        /// <returns></returns>
        public bool Exist(string name)
        {
            return GetAll().Any(u => u.Name == name); ;
        }
        #endregion

        #region CUD
        /// <summary>
        /// 新增管理员
        /// </summary>
        /// <param name="Name"></param>
        /// <param name="PhoneNum"></param>
        /// <param name="Password"></param>
        /// <param name="Email"></param>
        /// <param name="CityId"></param>
        /// <returns></returns>
        public long Add(string name,string password,  string phoneNum, string email, long? cityId)
        {
            string passwordSalt = CommonHelper.GenerateCaptchaCode(6);
            AdminUser user = new AdminUser();
            user.Name = name;
            user.PasswordSalt = passwordSalt;
            //MD5(MD5(用户名+用户输入密码+salt))
            user.PasswordHash = CommonHelper.CalcMD5(CommonHelper.CalcMD5(name + password + passwordSalt));
            user.PhoneNum = phoneNum;
            user.Email = email;
            user.IsEnable = true;
            if (cityId!=null)
            {
                user.CityId = cityId.Value;
            }
            return Add(user).Id;
        }

        /// <summary>
        /// 编辑用户
        /// </summary>
        /// <param name="Id"></param>
        /// <param name="phoneNum"></param>
        /// <param name="password"></param>
        /// <param name="email"></param>
        /// <param name="cityId"></param>
        public void Update(long id,  string password, string phoneNum, string email, long? cityId)
        {
            AdminUser user = GetById(id);
            if (user==null)
            {
                throw new Exception("获取不到管理员(Id:"+ id + ")信息");
            }
            if (!string.IsNullOrEmpty(password))
            {
                string passwordSalt = CommonHelper.GenerateCaptchaCode(6);
                user.PasswordSalt = passwordSalt;
                //MD5(MD5(用户名+用户输入密码+salt))
                user.PasswordHash = CommonHelper.CalcMD5(CommonHelper.CalcMD5(user.Name + password + passwordSalt));
            }
            user.PhoneNum = phoneNum;
            user.Email = email;
            if (cityId != null)
            {
                user.CityId = cityId.Value;
            }
            Update(user);
        }

        /// <summary>
        /// 改变管理员账号状态
        /// </summary>
        /// <param name="id"></param>
        /// <param name="isEnable"></param>
        /// <returns></returns>
        public bool ChangStatus(long id, bool isEnable)
        {
            AdminUser user = GetById(id);
            if (user == null)
            {
                throw new Exception("获取不到管理员信息");
            }
            user.IsEnable = isEnable;
            CurrentDal.Update(user);
            return DbSession.SaveChanges() > 0;
        } 
        #endregion

        #region 登录
        /// <summary>
        /// 验证登录
        /// </summary>
        /// <param name="userName"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        public AdminLoginResult CheckLogin(string userName, string password)
        {
            var user = GetAll().SingleOrDefault(u => u.Name == userName);
            if (user == null)
            {
                return AdminLoginResult.UserError;
            }
            //用户账号被禁用
            if (user.IsEnable == false)
            {
                return AdminLoginResult.UserDisable;
            }
            //用户账号被锁定
            if (user.LoginErrorTimes>=5&&user.LastLoginErrorDateTime>DateTime.Now.AddMinutes(-30))
            {
                return AdminLoginResult.UserLock;
            }

            string dbHash = user.PasswordHash;
            string userHash = CommonHelper.CalcMD5(CommonHelper.CalcMD5(user.Name + password + user.PasswordSalt));
            //比较数据库中的PasswordHash是否和MD5(MD5(用户名+用户输入密码+salt))一致
            return dbHash == userHash ? AdminLoginResult.Success : AdminLoginResult.UserError;
        }

        /// <summary>
        /// 登录成功
        /// </summary>
        /// <param name="userName"></param>
        public void LoginSuccess(string userName)
        {
            var users = GetAll().Where(u => u.Name == userName);
            if (users == null)
            {
                throw new ArgumentException("获取不到管理员信息");
            }
            if (users.Count() > 1)
            {
                throw new ArgumentException("获取到多个用户名为" + userName + "的管理员信息");
            }

            var user = users.Single();
            user.LoginErrorTimes = null;
            user.LastLoginErrorDateTime = null;
            CurrentDal.Update(user);
            DbSession.SaveChanges();
        }

        /// <summary>
        /// 登录失败
        /// </summary>
        /// <param name="userName"></param>
        public int LoginError(string userName)
        {
            var users = GetAll().Where(u => u.Name == userName);
            if (users == null)
            {
                throw new ArgumentException("获取不到管理员信息");
            }
            if (users.Count() > 1)
            {
                throw new ArgumentException("获取到多个用户名为" + userName + "的管理员信息");
            }

            var user = users.Single();
            //错误次数
            if (user.LoginErrorTimes == null)
            {
                user.LoginErrorTimes = 1;
            }
            else
            {
                user.LoginErrorTimes++;
            }
            user.LastLoginErrorDateTime = DateTime.Now;

            if (user.LoginErrorTimes>5)
            {
                return 0;
            }

            //超过错误次数，禁用用户
            //if (user.LoginErrorTimes >= 5)
            //{
            //    user.IsEnable = false;
            //}
            //if (user.LoginErrorTimes >= 10)
            //{
            //    throw new ArgumentException("管理员账号：" + userName + "多次尝试登录失败，登录行为异常");
            //}
            CurrentDal.Update(user);
            DbSession.SaveChanges();

            return 5- (int)user.LoginErrorTimes;
        }

        /// <summary>
        ///  验证用户是否拥有权限
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="controllerName"></param>
        /// <param name="actionName"></param>
        /// <param name="httpMethod"></param>
        /// <returns></returns>
        public bool HasPermission(long userId, string controllerName, string actionName, string httpMethod)
        {
            //方式1：
            var user = GetAll().AsNoTracking()
            .Include(u => u.AdminUserRoles)
            .Include(u => u.AdminUserRoles.Select(ar => ar.Role))
            .Include(u => u.AdminUserRoles.Select(ar => ar.Role).Select(r => r.RolePermissions))
            .Include(u => u.AdminUserRoles.Select(ar => ar.Role).Select(r => r.RolePermissions.Select(rp => rp.Permission)))
            .SingleOrDefault(u => u.Id == userId);

            //方式2：
            //var user = GetAll().AsNoTracking()
            //.Include(nameof(AdminUser.AdminUserRoles))
            //.Include(nameof(AdminUser.AdminUserRoles) + "." + nameof(AdminUserRole.Role))
            //.Include(nameof(AdminUser.AdminUserRoles) + "." + nameof(AdminUserRole.Role) + "." + nameof(Role.RolePermissions))
            //.Include(nameof(AdminUser.AdminUserRoles) + "." + nameof(AdminUserRole.Role) + "." + nameof(Role.RolePermissions) + "." + nameof(RolePermission.Permission))
            //.SingleOrDefault(u => u.Id == userId);


            //获取不到管理员信息
            if (user == null)
            {
                throw new ArgumentException("找不到id=" + userId + "的用户");
            }

            return user.AdminUserRoles
            .Select(ar => ar.Role)
            .SelectMany(r => r.RolePermissions)
            .Select(rp => rp.Permission)
            .Any(p => p.ControllerName.ToLower() == controllerName.ToLower()
            && p.ActionName.ToLower() == actionName.ToLower()
            && p.HttpMethod.ToLower().Contains(httpMethod.ToLower()));
        } 
        #endregion

        private AdminUserDTO ToDTO(AdminUser entity)
        {
            AdminUserDTO dto = new AdminUserDTO();
            dto.CreateDateTime = entity.CreateDateTime;
            dto.Id = entity.Id;
            dto.Name = entity.Name;
            dto.PhoneNum = entity.PhoneNum;
            dto.Email = entity.Email;
            dto.CityId = entity.CityId;
            if (entity.City != null)
            {
                dto.CityName = entity.City.Name;
            }
            else
            {
                dto.CityName = "总部";
            }
            dto.IsEnable = entity.IsEnable;
            dto.LoginErrorTimes = entity.LoginErrorTimes;
            dto.LastLoginErrorDateTime = entity.LastLoginErrorDateTime;
            dto.TryTimes = 5 - (entity.LoginErrorTimes == null ? 0 : (int)entity.LoginErrorTimes);

            dto.RoleIds = entity.AdminUserRoles.Select(ar => ar.Role.Id).ToList();
            dto.RoleNames = string.Join(",", entity.AdminUserRoles.Select(ar => ar.Role.Name));
            return dto;
        }
    }
}
